// pages/bluetooth/index.js
import { ab2hex, subData, hex2dex, hexToBase64, base64src, hexCharCodeToStr, codebuffer, integrateDataPackage } from '../../utils/data-handler-utils'
let disNetResMac = [], disNetResDid = [], packageNumsMac = 0, packageNumsDid = 0, picData= []
Page({

  /**
   * 页面的初始数据
   */
  data: {
    authBluetooth: false,
    connectedDeviceIds: [],
    connectedDeviceId: '',
    deviceList: [],
    services: [],
    characteristics: [],
    deviceResponse: null,
    imgData: [],
    imgSrc: '',
    analysisPic: ''
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /** 初始化蓝牙适配器 */
  openBluetoothAdapter(){
    this.closeBluetoothAdapter()
    console.log('初始化蓝牙适配器')
    wx.openBluetoothAdapter({
      success: (res) => {
        console.log(res);
        this.setData({
          authBluetooth: true
        })
      },
      fail: (err) => {
        console.log(err);
      }
    })
  },

  /** 搜索附近的蓝牙设备 */
  startBluetoothDevicesDiscovery(){
    console.log('开始搜索');
    this.data.authBluetooth && wx.startBluetoothDevicesDiscovery({
      // 广播包服务字段：0xFFFF（用于 app 扫描广播包，过滤设备）
      services: [], //只搜索广播包有对应 UUID 的主服务的蓝牙设备
      // services: ['FFFF'], //只搜索广播包有对应 UUID 的主服务的蓝牙设备
      allowDuplicatesKey: false,
      interval: 100, //上报间隔时间
      success: (res) => {
        console.log("搜索蓝牙设备：",res)
        if (!res.isDiscovering) { // 是否在搜索设备
          console.log("已经停止了")
        } else {
          this.data.timer = setInterval(() => {
            this.getBluetoothDevices()
          }, 5000)
        }
      },
      fail: function (err) {
        console.log("出错")
        console.log(err);
        if (err.errCode === 10008 && err.errno === 1500104) {
          wx.showModal({
            title: '出错了,操作太频繁了哟,请稍后重试',
            showCancel: false,
          })
        }
      }
    })
  },

  // 获取在蓝牙模块生效期间所有搜索到的蓝牙设备。包括已经和本机处于连接状态的设备。
  getBluetoothDevices(){
    let devices = []
    wx.getBluetoothDevices({
      success:  (res) => {
        console.log(res.devices)
        for (var i = 0; i < res.devices.length; i++) {
          // name蓝牙设备名称，某些设备可能没有, 过滤name(蓝牙设备的广播数据段中的 name 数据段)为JXBJ的设备,  res.devices[i].connectable可连接的设备 
          devices.push(res.devices[i])
          // if (res.devices[i].name != "未知设备" && res.devices[i].name.startsWith('JXBJ-')) {
          //   devices.push(res.devices[i])
          // }
        }
        if (devices.length === 0) return;

        // 找到要搜索的设备后，及时停止扫描
        wx.stopBluetoothDevicesDiscovery()
        wx.showToast({
          title: '搜索成功',
          icon: 'none',
          success: () => {
            clearInterval(this.data.timer)
            this.setData({deviceList: devices})
          }
        })
      },
      fail:  (err) => {
        console.log(err)
        if (err.errCode === 10001) {
          wx.showToast({
            title: '蓝牙连接断开,请打开蓝牙后重试',
            icon: 'none',
            duration: 2000,
            success: () => {
              // setTimeout(() => {
              //   wx.navigateBack()
              // }, 2000)
            }
          })
        }
      }
    })
  },

  connectTap(e){
    const {deviceId} = e.currentTarget.dataset
    console.log(deviceId);
    this.createBLEConnection(deviceId)
  },

   // 连接蓝牙低功耗设备。
  // 若小程序在之前已有搜索过某个蓝牙设备，并成功建立连接，可直接传入之前搜索获取的 deviceId 直接尝试连接该设备，无需再次进行搜索操作。
  createBLEConnection(deviceId){
    wx.createBLEConnection({
      deviceId: deviceId, //设备id
      success:  (res) => {
        console.log(res);
        console.log('成功连接设备：%s', deviceId);
        this.data.connectedDeviceId = deviceId
        this.data.connectedDeviceIds.push(deviceId)
        wx.showToast({
          title: '连接成功',
          duration: 800,
          mask: true
        })
        // 连接成功获取服务
        console.log('获取服务');
        this.getBLEDeviceServices(deviceId)
      },
      fail: err => {
        wx.showToast({
          title: '连接失败',
          icon: 'error',
          duration: 1000,
          mask: true
        })
        console.log("createBLEConnection连接失败", err)
      },
      complete: res => {
        console.log('createBLEConnection complete');
        // 监听蓝牙低功耗连接状态
        this.onBLEConnectionStateChange()
      }
    })
  },

  // 监听蓝牙低功耗连接状态
  onBLEConnectionStateChange(){
    // 监听蓝牙低功耗连接状态改变事件
    wx.onBLEConnectionStateChange((res) => {
      // connected	boolean	是否处于已连接状态
      // 该方法回调中可以用于处理连接意外断开等异常情况
      console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
      if (res.connected) {
        // this.globalData.instrumentInfo.isConnected = true
      }else{
        this.resetVariable('测肤精灵已断开连接，请检查设备是否关机或手机蓝牙关闭', 1, 3000)
      }
    })
  },

  // 获取服务
  getBLEDeviceServices(deviceId){
    wx.getBLEDeviceServices({
      deviceId, // 搜索到设备的 deviceId
      success: (res) => {
        console.log(res);
        this.data.services = res.services
        // 获取某一服务的所有特征值
        this.getBLEDeviceCharacteristics()
      },
      fail: err => {
        console.log('获取服务失败：');
        console.log(err);
      }
    })
  },

  // 获取某个服务的所有特征值
  getBLEDeviceCharacteristics(){
    var myuuid = this.data.services[0].uuid //具有读写通知属性的服务uuid
    wx.getBLEDeviceCharacteristics({
      // 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
      deviceId: this.data.connectedDeviceId,
      // deviceId: app.globalData.connectedDeviceId,
      // 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
      serviceId: myuuid,
      success:  (res) => {
        console.log(res);
        this.data.characteristics = res.characteristics
        this.notifyBLECharacteristicValueChange()
      },
      fail: function (err) {
        console.log("getBLEDeviceCharacteristics fail", err);
      }
    })
  },

  // 写特征值
  writeBLECharacteristicValue(buffer){
    console.log('写入');
    disNetResMac = []
    disNetResDid = []
    packageNumsMac = 0
    packageNumsDid = 0
    // if (!this.globalData.instrumentInfo.isConnected) return;
    if (this.data.services.length === 0) {
      wx.showToast({
        title: '请确保您的测肤仪处于连接状态',
        icon: 'none'
      })
    }else{
      // console.log(this.globalData.characteristics[0].properties.write);
      if (this.data.characteristics[0].properties.write) {
        // 写入
        wx.writeBLECharacteristicValue({
          characteristicId: this.data.characteristics[0].uuid,
          deviceId: this.data.connectedDeviceId,
          serviceId: this.data.services[0].uuid,
          value: buffer,
          success: res => {
            console.log('写入成功');
            console.log(res);
          },
          fail: err => {
            console.log('写入失败');
            console.log(err);
            if (err.errCode === 10006) {
              wx.hideLoading()
              wx.showToast({
                title: '未连接设备',
                icon: 'none'
              })
            }else if (err.errCode === 10008) {
              wx.hideLoading()
              wx.showToast({
                title: '系统错误，请重试',
                icon: 'none'
              })
            }else if (err.errCode === 10012) {
              wx.hideLoading()
              wx.showToast({
                title: '拍照超时，请重试',
                icon: 'none'
              })
            }
          }
        })
      }
      // this.onBLECharacteristicValueChange()
      // 如果有分析的图片，说明之前有picData中有数据
      if (this.data.imgSrc) {
        picData = []
      }
    }
  },

  // 启用蓝牙设备特征值变化时notify，开启监听
  notifyBLECharacteristicValueChange(){
    console.log('开始监听特征值的变化');
    wx.notifyBLECharacteristicValueChange({
      state: true, // 启用 notify 功能
      // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
      deviceId: this.data.connectedDeviceId,
      // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
      serviceId: this.data.services[0].uuid, // 电池电量
      // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
      characteristicId: this.data.characteristics[1].uuid,
      success: (res) => {
        console.log('success', res.errMsg)
        console.log('接收设备的返回信息');
        this.onBLECharacteristicValueChange()
      },
      fail: err => {
        console.log('notifyBLECharacteristicValueChange fail', err);
      },
    })
  },

  // 接收蓝牙设备返回消息
  onBLECharacteristicValueChange(){
    console.log('返回的消息开始');
    const { platform } = wx.getSystemInfoSync()
    const { connectedDeviceId } = this.data
    if (platform === 'android'){
      // 设置MTU
      wx.setBLEMTU({
        deviceId: connectedDeviceId,
        mtu: 256,
        success: res => {
          console.log('设置MTU');
          console.log(res);
        },
        fail: err => {
          console.log(err);
        }
      })
    }
    // 监听蓝牙低功耗设备的特征值变化事件。必须先调用 wx.notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification
    wx.onBLECharacteristicValueChange(res => {
      let result = ab2hex(res.value)
      if (this.data.deviceResponse == result) {
        return;
      }else{
        this.data.deviceResponse = result
        console.log('characteristic value comed:')
        console.log('characteristic value comed:', ab2hex(res.value))
        const protocolHeader = subData(ab2hex(res.value), 0, 2)
        // 0xC0 充电状态及电量
        if (protocolHeader === 'c0') {
          const dataDomain = subData(subData(ab2hex(res.value), -28), 0, 26)
          // 供电方式
          const powerSupplyMode = subData(dataDomain, 0, 2)
          // 充电状态
          const chargeState = subData(dataDomain, 2, 2)
          // 电量
          const battary = hex2dex(subData(dataDomain, 4, 2))
          // // console.log('供电方式:', powerSupplyMode);
          // // console.log('充电状态:', chargeState);
          // if (powerSupplyMode === '01') {
          //   console.log('供电方式:USB供电');
          //   if (chargeState === '01') {
          //     console.log('充电状态：正在充电');
          //   }else if(chargeState === '00'){
          //     console.log('充电状态：充满');
          //   }
          // }else if (powerSupplyMode === '00') {
          //   console.log('供电方式:电池供电');
          // }
          console.log('电量：', battary + '%');
        }
        // 0xD0  传图
        if (protocolHeader === 'd0') {
          // const packageNumberHex = subData(ab2hex(res.value), 8, 2)
          // const packageNumber = hex2dex(subData(ab2hex(res.value), 8, 2))
          const dataLen = hex2dex(subData(ab2hex(res.value), 10, 2)) * 2
          const imgDataDomain = subData(ab2hex(res.value), 12, dataLen)
          // console.log(packageNumberHex, packageNumber, imgDataDomain.length);
          picData.push(imgDataDomain)
          // this.globalData.imgData.push(imgDataDomain)
          // let data = this.globalData.imgData.join('')
          let data = picData.join('')
          let base64String = hexToBase64(data)
          let imgSrc = `data:image/jpg;base64,${base64String}`
          // this.globalData.imgSrc = imgSrc

          // console.log(data.startsWith('ffd8'));
          // console.log(data.endsWith('ffd9'));

          if (data.startsWith('ffd8') && data.endsWith('ffd9')) {
            base64src(imgSrc, (res) => {
              console.log('返回的消息结束');
              console.log(res); //转换后的临时链接地址
              this.data.analysisPic = res
              // this.data.imgSrc = res
              this.setData({imgSrc: res})
              // 关闭当前页面，跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。
              wx.hideLoading()
              // 延迟三秒，用户优化全脸拍摄所有部位后，仍处于拍照的状态  该问题不优化
              // setTimeout(() => {
              //   wx.hideLoading()
              // }, 3000);
            })
          }
        }
        // 0xB0  配网
        if (protocolHeader === 'b0') {
          // 配网结果
          const distriNetRes = subData(ab2hex(res.value), 2, 2)
          // 字段类型
          const dataType = subData(ab2hex(res.value), 4, 2)
          // 分包数
          const packageNums = hex2dex(subData(ab2hex(res.value), 4, 2)) === 0 ? 1 : hex2dex(subData(ab2hex(res.value), 4, 2))
          // 包号
          const packageNumber = hex2dex(subData(ab2hex(res.value), 8, 2))
          // 数据长度
          const dataLen = hex2dex(subData(ab2hex(res.value), 10, 2)) * 2
          // 数据域
          const imgDataDomain = subData(ab2hex(res.value), 12, dataLen)

          if (dataType === '01') { //// Mac
            disNetResMac.push(imgDataDomain)
            packageNumsMac = parseInt(packageNums)
          }else if (dataType === '02') { //DID
            disNetResDid.push(imgDataDomain)
            packageNumsDid = parseInt(packageNums)
          }

          if (distriNetRes === '01') {
            if ((packageNumsMac + packageNumsDid) === (disNetResMac.length + disNetResDid.length) && disNetResDid.length !== 0) {
                console.log('配网后返回的MAC', hexCharCodeToStr(disNetResMac.join('')));
                console.log('配网后返回的DiD', hexCharCodeToStr(disNetResDid.join('')));
                console.log('配网成功');
                this.globalData.isDistributeNetwork = true
                wx.hideLoading()
                wx.showToast({
                  title: '测肤仪配网成功',
                  success: res => {
                    let storageInfo = wx.getStorageSync('distributeNet')
                    if (!storageInfo) {
                      wx.setStorageSync('distributeNet', [{
                        SSID: this.globalData.ssid,
                        distributeRes: this.globalData.isDistributeNetwork,
                        deviceMac: hexCharCodeToStr(disNetResMac.join(''))
                      }])
                    }else{
                      storageInfo.push({
                        SSID: this.globalData.ssid,
                        distributeRes: this.globalData.isDistributeNetwork,
                        deviceMac: hexCharCodeToStr(disNetResMac.join(''))
                      })
                      console.log(storageInfo);
                      // 将配网的SSID和已经配网存在本地，用于当用户使用wifi拍照时直接获取设备IP
                      wx.setStorageSync('distributeNet', storageInfo)
                    }
                  }
                })
                // 配网成功后获取设备Ip
                // console.log('开始获取设备Ip');
            }
          }else{
            disNetResMac = []
            disNetResDid = []
            packageNumsMac = 0
            packageNumsDid = 0
            wx.showLoading({
              title: '设备配网中...',
            })
          }
        }
        // 清除配网结果
        if (ab2hex(res.value) === 'a001080057') {
          console.log('ble清除配网');
          this.getConnectedWifi().then(res => {
            if (res.errCode === 0) {
              const SSID = res.wifi.SSID
              let newStorageInfo = wx.getStorageSync('distributeNet').filter(item => {
                return item.SSID !== SSID
              })
              console.log(newStorageInfo);
              // 将配网的SSID和已经配网存在本地，用于当用户使用wifi拍照时直接获取设备IP
              wx.setStorageSync('distributeNet', newStorageInfo)
              this.globalData.isDistributeNetwork = false
            }
          })
        }
      }
    })
  },

  getPic(){
    let that = this
    if (that.data.imgData.length !== 0) {
      that.setData({
        imgData: []
      })
    }
    const picData = ''
    const integratePicData = integrateDataPackage(picData, '07')
    console.log(integratePicData);
    // 向设备发送拍照指令 有几个包就发几次
    for (let i = 0; i < integratePicData.length; i++) {
      // 截取每一个包的数据
      let picCode = integratePicData[i]
      that.writeBLECharacteristicValue(codebuffer(picCode))
    }
  },

  
  /**
   * 连接断开重置变量
   * @param {*} tip 提示标题
   * @param {*} ways 主动断开连接0，异常断开1
   * @param {*} duration 提示持续的时间
   */
  resetVariable(tip, ways=1, duration=1500){
    this.data.deviceLists = []
    this.data.isConnected =  false
    this.data.connectedDeviceId =  ''
    this.data.services = []
    this.data.characteristics = []
    if (ways === 0) {
      wx.showToast({
        title: tip,
        icon: 'none',
        duration,
        success: () => {
          this.closeBluetoothAdapter()
        }
      })
    }else if(ways === 1){
      wx.showModal({
        title: tip,
        showCancel: false,
        confirmColor: '#C5AF6F',
        complete: (res) => {
          if (res.confirm) {
            this.closeBluetoothAdapter()
          }
        }
      })
    }
  },

  /** 关闭蓝牙适配器 */
  closeBluetoothAdapter(){
    console.log('关闭蓝牙适配器')
    wx.closeBluetoothAdapter()
  }
})